home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / gnu / emacs_src_18_58.lha / emacs-18.58 / src / amiga_malloc.c < prev    next >
C/C++ Source or Header  |  1992-08-17  |  8KB  |  333 lines

  1. /* Emulation of some unix functions for emacs.
  2. Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU Emacs.
  5.  
  6. GNU Emacs is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY.  No author or distributor
  8. accepts responsibility to anyone for the consequences of using it
  9. or for whether it serves any particular purpose or works at all,
  10. unless he says so in writing.  Refer to the GNU Emacs General Public
  11. License for full details.
  12.  
  13. Everyone is granted permission to copy, modify and redistribute
  14. GNU Emacs, but only under the conditions described in the
  15. GNU Emacs General Public License.   A copy of this license is
  16. supposed to have been given to you along with GNU Emacs so you
  17. can know your rights and responsibilities.  It should be in a
  18. file named COPYING.  Among other things, the copyright notice
  19. and this notice must be preserved on all copies.  */
  20.  
  21. #include <exec/types.h>
  22. #include <exec/memory.h>
  23. #include <proto/exec.h>
  24.  
  25. #undef LONGBITS
  26. #undef NULL
  27. #include "config.h"
  28. #include "lisp.h"
  29. #include "amiga.h"
  30.  
  31. /* Memory stuff */
  32. long far DataSegBits;
  33. static int DataSegFound;
  34. static struct mem_header *far current;
  35. struct mem_header *free_list;
  36. extern int alloca_calling;
  37. extern int *pure;
  38. long far pre_alloc;    /* amount of memory to reserve for emacs */
  39. char *malloc_hunk;
  40. long malloc_hunk_size = MALLOC_HUNK_SIZE; /* Amount of memory malloc'ed by a
  41.                          to-be-dumped emacs */
  42. long malloc_bytes_used;    /* Amount of this hunk actually used */
  43. static int early_malloc = TRUE;    /* Before we undump, we want system allocations */
  44.  
  45. #define ADDR_OK(x) (((long)x & ~VALMASK) == DataSegBits)
  46.  
  47. /* Memory allocation code */
  48. /* ---------------------- */
  49.  
  50. static void *alloc_sys(long memsize)
  51. /* Effect: Allocate from AmigaOS (via AllocMem). */
  52. {
  53.   /* Allocation rounded up to multiple of 4 */
  54.   long size = ((memsize + 3) & ~3) + sizeof(struct mem_header);
  55.   struct mem_header *mem;
  56.  
  57.   if (!DataSegFound)
  58.     {
  59.       /* Find page containing Pure data. All data used by emacs must be
  60.      on the same page (As a page is 2^26 bytes, this shouldn't be too
  61.      unlikely). */
  62.       DataSegBits = (long)&first_data & ~VALMASK;
  63.       if (!(ADDR_OK(first_fn) && ADDR_OK(last_fn) &&
  64.         ADDR_OK(&first_data) && ADDR_OK(&last_data) &&
  65.         ADDR_OK(&first_bss) && ADDR_OK(&last_bss)))
  66.     _fail("I can't handle your memory configuration");
  67.       DataSegFound = TRUE;
  68.     }
  69.  
  70.   mem = AllocMem(size, 0);
  71.   if (!mem) return 0;
  72.   /* All memory *must* be allocated on the same page ! */
  73.   if (!ADDR_OK(mem))
  74.     {
  75.       FreeMem(mem, size);
  76.       return 0;
  77.     }
  78.   if (current) current->prev = mem;
  79.   mem->next = current;
  80.   mem->prev = 0;
  81.   current = mem;
  82.   mem->size = size;
  83.  
  84.   return mem + 1;
  85. }
  86.  
  87. static void free_sys(char *p)
  88. {
  89.   struct mem_header *old = (struct mem_header *)p - 1;
  90.  
  91.   if (old == current)
  92.     {
  93.       current = current->next;
  94.       if (current) current->prev = 0;
  95.     }
  96.   else
  97.     {
  98.       old->prev->next = old->next;
  99.       if (old->next) old->next->prev = old->prev;
  100.     }
  101.   FreeMem(old, old->size);
  102. }
  103.  
  104. void MemCleanup(void)
  105. {
  106.   struct mem_header *next;
  107.  
  108.   while (current)
  109.     {
  110.       next = current->next;
  111.       FreeMem(current, current->size);
  112.       current = next;
  113.     }
  114. }
  115.  
  116. static void *alloc_hunk(long memsize)
  117. /* Effect: Allocates from the malloc hunk (which is dumped to disk).
  118. */
  119. {
  120.   /* Allocation rounded up to multiple of 4 */
  121.   long size = ((memsize + 3) & ~3) + sizeof(struct mem_header);
  122.   /* Find a free block in the memory list */
  123.   struct mem_header *scan = free_list->next;
  124.  
  125.   while (scan->size > 0)
  126.     {
  127.       if (size < scan->size)    /* Found ! */
  128.     {
  129.       long end;
  130.  
  131.       /* Split block if big enough */
  132.       if (size + sizeof(struct mem_header) + 8 > scan->size)
  133.         {
  134.           /* Remove block from list */
  135.           scan->prev->next = scan->next;
  136.           scan->next->prev = scan->prev;
  137.         }
  138.       else
  139.         {
  140.           /* Split block */
  141.           struct mem_header *new = (struct mem_header *)((char *)scan + size);
  142.  
  143.           new->prev = scan->prev;
  144.           new->next = scan->next;
  145.           scan->prev->next = new;
  146.           scan->next->prev = new;
  147.           new->size = scan->size - size;
  148.           scan->size = size;
  149.         }
  150.       if (!amiga_initialized)
  151.         {
  152.           end = (char *)scan - (char *)free_list + scan->size +
  153.         sizeof(long) + sizeof(struct mem_header);
  154.           if (end > malloc_bytes_used) malloc_bytes_used = end;
  155.         }
  156.       return scan + 1;
  157.     }
  158.       scan = scan->next;
  159.     }
  160.   return 0;
  161. }
  162.  
  163. static void free_hunk(char *p)
  164. {
  165.   struct mem_header *old = (struct mem_header *)p - 1, *scan = free_list;
  166.  
  167.   do scan = scan->next; while (scan < old);
  168.  
  169.   /* Check for merges (potentially with both sides) */
  170.   if ((char *)scan->prev + scan->prev->size == (char *)old)
  171.     if ((char *)old + old->size == (char *)scan)
  172.       {
  173.     /* Merge all 3 blocks together */
  174.     scan->prev->size += old->size + scan->size;
  175.     scan->next->prev = scan->prev;
  176.     scan->prev->next = scan->next;
  177.       }
  178.     else            /* Merge with previous block */
  179.       scan->prev->size += old->size;
  180.   else if ((char *)old + old->size == (char *)scan)
  181.     {
  182.       /* Merge with next block */
  183.       old->size += scan->size;
  184.       scan->prev->next = old;
  185.       scan->next->prev = old;
  186.       old->prev = scan->prev;
  187.       old->next = scan->next;
  188.     }
  189.   else                /* Add a new block */
  190.     {
  191.       old->next = scan;
  192.       old->prev = scan->prev;
  193.       scan->prev->next = old;
  194.       scan->prev = old;
  195.     }
  196. }
  197.  
  198. char *malloc(long size)
  199. {
  200.   if (early_malloc) return alloc_sys(size);
  201.  
  202.   if (!amiga_initialized)
  203.     if (alloca_calling)
  204.       {
  205.     alloca_calling = 0;
  206.     return alloc_sys(size);
  207.       }
  208.     else
  209.       {
  210.     void *mem = alloc_hunk(size);
  211.  
  212.     if (!mem) 
  213.       _fail("Emacs dump: ran out of memory for malloc. \n"
  214.         "See the -malloc option for more information.\n");
  215.     return mem;
  216.       }
  217.   else
  218.     {
  219.       alloca_calling = 0;
  220.       if (pre_alloc)
  221.     {
  222.       void *mem;
  223.  
  224.       if (mem = alloc_hunk(size)) return mem;
  225.     }
  226.       return alloc_sys(size);
  227.     }
  228. }
  229.  
  230. free(void *p)
  231. {
  232.   struct mem_header *old = (struct mem_header *)p - 1;
  233.  
  234.   if ((char *)p >= malloc_hunk &&
  235.       (char *)p <= malloc_hunk + malloc_hunk_size + pre_alloc)
  236.     {
  237.       if (!amiga_initialized || pre_alloc) free_hunk(p);
  238.     }
  239.   else free_sys(p);
  240. }
  241.  
  242. void *getml(long size)
  243. {
  244.   return malloc(size);
  245. }
  246.  
  247. int rlsml(char *p, long size)
  248. {
  249.   struct mem_header *old = (struct mem_header *)p - 1;
  250.   long rsize = ((size + 3) & ~3) + sizeof(struct mem_header);
  251.  
  252.   if (old->size != rsize) abort();
  253.  
  254.   free(p);
  255.   return 0;
  256. }
  257.  
  258. char *calloc(long n, long size)
  259. {
  260.   char *t;
  261.   long rsize = n * size;
  262.  
  263.   t = malloc(rsize);
  264.   if (t) memset (t, 0, rsize);
  265.  
  266.   return t;
  267. }
  268.  
  269. char *realloc(char *p, long size)
  270. {
  271.   char *new = malloc(size);
  272.   struct mem_header *old = (struct mem_header *)p - 1;
  273.  
  274.   if (new)
  275.     {
  276.       long minsize;
  277.       long oldsize = old->size - sizeof(struct mem_header);
  278.  
  279.       if (size < oldsize) minsize = size;
  280.       else minsize = oldsize;
  281.  
  282.       memcpy(new, p, minsize);
  283.     }
  284.   free(p);
  285.   return new;
  286. }
  287.  
  288. void emacs_malloc_init(void)
  289. {
  290.   struct mem_header *end_sentinel, *new_end, *new_block;
  291.  
  292.   early_malloc = FALSE;        /* We now have a malloc hunk */
  293.  
  294.   /* Set up the memory allocation in the malloc hunk */
  295.   free_list = (struct mem_header *)malloc_hunk;
  296.   end_sentinel = (struct mem_header *)((char *)free_list + malloc_hunk_size
  297.                        - sizeof(struct mem_header));
  298.   if (!amiga_initialized)
  299.     {
  300.       /* Before dumping */
  301.       free_list->next = free_list + 1;
  302.       free_list->prev = 0;
  303.       free_list->size = 0;    /* Prevents merges with this pseudo-block */
  304.       free_list[1].prev = free_list;
  305.       free_list[1].next = end_sentinel;
  306.       free_list[1].size =
  307.     malloc_hunk_size - 2 * sizeof(struct mem_header) - sizeof(long);
  308.       /* The - sizeof(long) prevents any merges with end_sentinel */
  309.  
  310.       end_sentinel->size = 0;
  311.       end_sentinel->prev = free_list + 1;
  312.       end_sentinel->next = 0;
  313.  
  314.       malloc_bytes_used = 0;
  315.     }
  316.   else if (pre_alloc)
  317.     {
  318.       /* After having undumped extend malloc block */
  319.       /* Move end_sentinel: */
  320.       new_end = (struct mem_header *)((char *)free_list + malloc_hunk_size +
  321.                       pre_alloc - sizeof(struct mem_header));
  322.       new_end->size = 0;
  323.       new_end->next = 0;
  324.       new_end->prev = end_sentinel->prev;
  325.       end_sentinel->prev->next = new_end;
  326.  
  327.       /* Add extra memory (pre_alloc bytes) */
  328.       new_block = (struct mem_header *)((char *)end_sentinel - sizeof(long));
  329.       new_block->size = pre_alloc;
  330.       free_hunk((char *)(new_block + 1));
  331.     }
  332. }
  333.